export type IterableBaseOptions<R, V> = {
  toValueFn?: (rawValue: R) => V;
}

export abstract class IterableBase<R, V> {
  private toValueFn: IterableBaseOptions<R, V>['toValueFn']

  protected constructor(optinos?: IterableBaseOptions<R, V>) {
    if (optinos) {
      const { toValueFn } = optinos
      if (typeof toValueFn === 'function') {
        this.toValueFn = toValueFn
      } else if (toValueFn) {
        throw new TypeError('toValueFn must be a function type')
      }
    }
  }

  get getToValueFn(): IterableBaseOptions<R, V>['toValueFn'] {
    return this.toValueFn
  }

  * [Symbol.iterator](...args: any[]): IterableIterator<V> {
    yield* this.getIterator(...args)
  }

  abstract get size(): number;

  abstract isEmpty(): boolean;

  abstract clear(): void;

  protected abstract getIterator(...args: any[]): IterableIterator<V>;
}
